#include "Ast.h"
#include "SymbolTable.h"
#include "Unit.h"
#include "Instruction.h"
#include "IRBuilder.h"
#include <string>
#include "Type.h"
#include <assert.h>
extern FILE *yyout;
int Node::counter = 0;
IRBuilder *Node::builder = nullptr;
int genBr = 0; // 优化用，生成跳转指令
bool funcReturned = false;
Type* returnType = nullptr;
Node::Node()
{
    seq = counter++;
}

void Node::backPatch(std::vector<Instruction *> &list, BasicBlock *bb)
{
    for (auto &inst : list)
    {
        if (inst->isCond())
            dynamic_cast<CondBrInstruction *>(inst)->setTrueBranch(bb);
        else if (inst->isUncond())
        {
            dynamic_cast<UncondBrInstruction *>(inst)->setBranch(bb);
        }
    }
}

std::vector<Instruction *> Node::merge(std::vector<Instruction *> &list1, std::vector<Instruction *> &list2)
{
    std::vector<Instruction *> res(list1);
    res.insert(res.end(), list2.begin(), list2.end());
    return res;
}

void Ast::genCode(Unit *unit)
{
    IRBuilder *builder = new IRBuilder(unit);
    Node::setIRBuilder(builder);
    root->genCode();
}

void BinaryExpr::genCode()
{
    std::cout << "Entering BinaryExpr::genCode" << std::endl;
    BasicBlock *bb = builder->getInsertBB();
    Function *func = bb->getParent();

    if (op == AND)
    {
        BasicBlock *trueBB = new BasicBlock(func); // if the result of lhs is true, jump to the trueBB.
        genBr = 1;
        expr1->genCode();
        backPatch(expr1->trueList(), trueBB);
        builder->setInsertBB(trueBB); // set the insert point to the trueBB so that intructions generated by expr2 will be inserted into it.
        expr2->genCode();
        true_list = expr2->trueList();
        false_list = merge(expr1->falseList(), expr2->falseList());
    }
    else if (op == OR)
    {
        // TODO: 实现 OR 操作符的逻辑
        BasicBlock *falseBB = new BasicBlock(func); // if the result of lhs is false, jump to the falseBB.
        genBr = 1;
        expr1->genCode();
        backPatch(expr1->falseList(), falseBB);
        builder->setInsertBB(falseBB); // set the insert point to the falseBB so that instructions generated by expr2 will be inserted into it.
        expr2->genCode();
        true_list = merge(expr1->trueList(), expr2->trueList());
        false_list = expr2->falseList();
    }
    else if (op >= LESS && op <= NEQ)
    {
        // TODO: 实现关系操作符 (LESS, GREATER, LEQ, GEQ, EQ, NEQ) 的逻辑
        genBr--;
        expr1->genCode();
        expr2->genCode();
        genBr++;

        int opcode = -1;
        switch (op)
        {
        case LESS:
            opcode = CmpInstruction::L;
            break;
        case LEQ:
            opcode = CmpInstruction::LE;
            break;
        case GREATER:
            opcode = CmpInstruction::G;
            break;
        case GEQ:
            opcode = CmpInstruction::GE;
            break;
        case EQ:
            opcode = CmpInstruction::E;
            break;
        case NEQ:
            opcode = CmpInstruction::NE;
            break;
        }
        new CmpInstruction(opcode, dst, expr1->getOperand(), expr2->getOperand(), bb);

        if (genBr > 0)
        {
            // 跳转目标block
            BasicBlock *trueBlock, *falseBlock, *mergeBlock;
            trueBlock = new BasicBlock(func);
            falseBlock = new BasicBlock(func);
            mergeBlock = new BasicBlock(func);
            true_list.push_back(new CondBrInstruction(trueBlock, falseBlock, dst, bb));
            false_list.push_back(new UncondBrInstruction(mergeBlock, falseBlock));
        }
    }
    else if (op >= ADD && op <= MOD)
    {
        expr1->genCode();
        expr2->genCode();
        Operand *src1 = expr1->getOperand();
        Operand *src2 = expr2->getOperand();
        int opcode;
        switch (op)
        {
        case ADD:
            opcode = BinaryInstruction::ADD;
            break;
        case SUB:
            opcode = BinaryInstruction::SUB;
            break;
        case MUL:
            opcode = BinaryInstruction::MUL;
            break;
        case DIV:
            opcode = BinaryInstruction::DIV;
            break;
        case MOD:
            opcode = BinaryInstruction::MOD;
            break;
        default:
            opcode = -1;
            break;
        }
        new BinaryInstruction(opcode, dst, src1, src2, bb);
    }
}

void Constant::genCode()
{
    // we don't need to generate code.
}

void Id::genCode()
{
    // std::cout << "Entering genCode::genCode" << std::endl;

    BasicBlock *bb = builder->getInsertBB();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry *>(symbolEntry)->getAddr();
    new LoadInstruction(dst, addr, bb);
}

void IfStmt::genCode()
{
    std::cout << "Entering IfStmt::genCode" << std::endl;
    Function *func;
    BasicBlock *then_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    genBr = 1;
    cond->genCode();
    backPatch(cond->trueList(), then_bb);
    backPatch(cond->falseList(), end_bb);

    builder->setInsertBB(then_bb);
    thenStmt->genCode();
    then_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, then_bb);

    builder->setInsertBB(end_bb);
}

void IfElseStmt::genCode()
{
    // TODO: 实现 IfElse 语句的代码生成逻辑
    std::cout << "Entering IfElseStmt::genCode" << std::endl;
    Function *func;
    BasicBlock *then_bb, *else_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    else_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    genBr = 1;
    cond->genCode();
    backPatch(cond->trueList(), then_bb);
    backPatch(cond->falseList(), else_bb);

    // 先处理then分支
    builder->setInsertBB(then_bb);
    thenStmt->genCode();
    then_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, then_bb);

    // 再处理else分支
    builder->setInsertBB(else_bb);
    elseStmt->genCode();
    else_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, else_bb);

    builder->setInsertBB(end_bb);
}

void CompoundStmt::genCode()
{
    // TODO: 实现复合语句的代码生成逻辑
    stmt->genCode();
}

void SeqNode::genCode()
{
    // TODO: 实现序列节点的代码生成逻辑
    for (auto stmt : stmtList)
    {
        stmt->genCode();
    }
}

void DeclStmt::genCode()
{
    for (auto stmt : defList)
    {
        stmt->genCode();
    }
}

void DefNode::genCode()
{
    Operand *addr;
    IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>(id->getSymPtr());
    if (se->isGlobal())
    {
        SymbolEntry *addr_se;
        addr_se = new IdentifierSymbolEntry(*se);
        addr_se->setType(new PointerType(se->getType()));
        addr = new Operand(addr_se);
        se->setAddr(addr);
        this->builder->getUnit()->insertDecl(se);
    }
    else
    {
        Function *func = builder->getInsertBB()->getParent();
        BasicBlock *entry = func->getEntry();
        Instruction *alloca;
        SymbolEntry *addr_se;
        Type *type;
        type = new PointerType(se->getType());
        addr_se = new TemporarySymbolEntry(type, SymbolTable::getLabel());
        addr = new Operand(addr_se);
        alloca = new AllocaInstruction(addr, se); // allocate space for local id in function stack.
        entry->insertFront(alloca);               // allocate instructions should be inserted into the begin of the entry block.
        se->setAddr(addr);                        // set the addr operand in symbol entry so that we can use it in subsequent code generation.
    }
}

void ContinueStmt::genCode()
{
    assert(whileStack.size() != 0);
    Function *func = builder->getInsertBB()->getParent();
    BasicBlock *bb = builder->getInsertBB();
    // 首先获取当前所在的while
    WhileStmt *whileStmt = whileStack.top();
    // 获取条件判断block
    BasicBlock *cond_bb = whileStmt->getCondBlock();
    // 在当前基本块中生成一条跳转到条件判断的语句
    new UncondBrInstruction(cond_bb, bb);
    // 声明一个新的基本块用来插入后续的指令
    BasicBlock *nextBlock = new BasicBlock(func);
    builder->setInsertBB(nextBlock);
}

void BreakStmt::genCode()
{
    assert(whileStack.size() != 0);
    Function *func = builder->getInsertBB()->getParent();
    BasicBlock *bb = builder->getInsertBB();
    // 首先获取当前所在的while
    WhileStmt *whileStmt = whileStack.top();
    // 获取条件判断block
    BasicBlock *end_bb = whileStmt->getEndBlock();
    // 在当前基本块中生成一条跳转到条件判断的语句
    new UncondBrInstruction(end_bb, bb);
    // 声明一个新的基本块用来插入后续的指令
    BasicBlock *nextBlock = new BasicBlock(func);
    builder->setInsertBB(nextBlock);
}

void ReturnStmt::genCode()
{
    // TODO: 实现返回语句的代码生成逻辑
    BasicBlock *bb = builder->getInsertBB();
    if (retValue != nullptr)
    {
        retValue->genCode();
        Operand *operand = retValue->getOperand();
        new RetInstruction(operand, bb);
    }
    else
    {
        new RetInstruction(nullptr, bb);
    }
}

void AssignStmt::genCode()
{
    // TODO: 实现赋值语句的代码生成逻辑
    BasicBlock *bb = builder->getInsertBB();
    expr->genCode();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry *>(lval->getSymPtr())->getAddr();
    Operand *src = expr->getOperand();

    new StoreInstruction(addr, src, bb);
}

void WhileStmt::genCode()
{
    // 将当前的whileStmt压栈
    whileStack.push(this);
    Function *func = builder->getInsertBB()->getParent();
    BasicBlock *stmt_bb, *cond_bb, *end_bb, *bb = builder->getInsertBB();
    stmt_bb = new BasicBlock(func);
    cond_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    this->condBlock = cond_bb;
    this->endBlock = end_bb;

    // 先从当前的bb跳转到cond_bb进行条件判断
    new UncondBrInstruction(cond_bb, bb);

    // 调整插入点到cond_bb，对条件判断部分生成中间代码
    builder->setInsertBB(cond_bb);
    genBr = 1;
    Cond->genCode();
    backPatch(Cond->trueList(), stmt_bb);
    backPatch(Cond->falseList(), end_bb);

    // 调整插入点到stmt_bb，对循环体部分生成中间代码
    builder->setInsertBB(stmt_bb);
    stmt->genCode();
    // 循环体完成之后，增加一句无条件跳转到cond_bb
    stmt_bb = builder->getInsertBB();
    new UncondBrInstruction(cond_bb, stmt_bb);

    // 重新调整插入点到end_bb
    builder->setInsertBB(end_bb);

    // 将当前的whileStmt出栈
    whileStack.pop();
}


void ForStmt::genCode()
{
    // 将当前的forStmt压栈
    forStack.push(this);
    Function *func = builder->getInsertBB()->getParent();
    BasicBlock *init_bb, *cond_bb, *stmt_bb, *loop_bb, *end_bb, *bb=builder->getInsertBB();
    
    init_bb = new BasicBlock(func);
    cond_bb = new BasicBlock(func);
    stmt_bb = new BasicBlock(func);
    loop_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    this->condBlock = cond_bb;
    this->endBlock = end_bb;
    this->loopBlock = loop_bb;
    this->initBlock = init_bb;

    
    // 先从当前的bb跳转到init_bb进行初始化
    new UncondBrInstruction(init_bb, bb);

    // 生成初始化部分的代码
    builder->setInsertBB(init_bb);
    initStmt->genCode();
    new UncondBrInstruction(cond_bb, init_bb);

    // 生成条件判断部分的代码
    builder->setInsertBB(cond_bb);
    genBr = 1;
    Cond->genCode();
    backPatch(Cond->trueList(), stmt_bb);
    backPatch(Cond->falseList(), end_bb);

    // 整插入点到stmt_bb，对循环体部分生成中间代码
    builder->setInsertBB(stmt_bb);
    stmt->genCode();
    stmt_bb = builder->getInsertBB();
    new UncondBrInstruction(loop_bb, stmt_bb);

    // 生成更新部分的代码
    builder->setInsertBB(loop_bb);
    loopStmt->genCode();
    new UncondBrInstruction(cond_bb, loop_bb);

    // 设置插入点到结束基本块
    builder->setInsertBB(end_bb);

    // 将当前的forStmt出栈
    forStack.pop();
}

void IOStmt::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    if (op == PRINT)
    {
        // 生成打印语句的代码
        expr->genCode();
        Operand *src = expr->getOperand();
        // 假设我们有一个 PrintInstruction 类来处理打印操作
        new PrintInstruction(src, bb);
    }
    else if (op == SCAN)
    {
        // 生成扫描语句的代码
        Operand *addr = dynamic_cast<IdentifierSymbolEntry *>(expr->getSymPtr())->getAddr();
        // 假设我们有一个 ScanInstruction 类来处理扫描操作
        new ScanInstruction(addr, bb);
    }
}


// main function
void FunctionDef::genCode()
{
    Unit *unit = builder->getUnit();
    Function *func = new Function(unit, se);
    BasicBlock *entry = func->getEntry();
    // set the insert point to the entry basicblock of this function.
    builder->setInsertBB(entry);

    stmt->genCode();

    /**
     * Construct control flow graph. You need do set successors and predecessors for each basic block.
     * Todo
     */
    // 遍历Function中所有的BasicBlock，在各个BasicBlock之间建立控制流关系
    for (auto block = func->begin(); block != func->end(); block++)
    {
        // 清除ret之后的全部指令
        Instruction *index = (*block)->begin();
        while (index != (*block)->end())
        {
            if (index->isRet())
            {
                while (index != (*block)->rbegin())
                {
                    (*block)->remove(index->getNext());
                }
                break;
            }
            index = index->getNext();
        }
        // 获取该块的最后一条指令
        Instruction *last = (*block)->rbegin();
        // (*block)->output();
        // 对于有条件的跳转指令，需要对其true分支和false分支都设置控制流关系
        if (last->isCond())
        {
            BasicBlock *trueBlock = dynamic_cast<CondBrInstruction *>(last)->getTrueBranch();
            BasicBlock *falseBlock = dynamic_cast<CondBrInstruction *>(last)->getFalseBranch();
            (*block)->addSucc(trueBlock);
            (*block)->addSucc(falseBlock);
            trueBlock->addPred(*block);
            falseBlock->addPred(*block);
        }
        // 对于无条件的跳转指令，只需要对其目标基本块设置控制流关系即可
        if (last->isUncond())
        {
            BasicBlock *dstBlock = dynamic_cast<UncondBrInstruction *>(last)->getBranch();
            (*block)->addSucc(dstBlock);
            dstBlock->addPred(*block);
        }
    }
}

void Ast::typeCheck(Node **parentToChild)
{
    // TODO: 实现抽象语法树的类型检查逻辑

    if (root != nullptr)
        root->typeCheck(nullptr);
    printf("Type check finished\n");
}

void BinaryExpr::typeCheck(Node **parentToChild)
{
    // TODO: 实现二元表达式的类型检查逻辑

    expr1->typeCheck((Node **)&(this->expr1));
    if (expr2 == nullptr)
    { 
        return;
    }
    expr2->typeCheck((Node **)&(this->expr2));

    Type *type1 = expr1->getSymPtr()->getType();
    Type *type2 = expr2->getSymPtr()->getType();
    if (type2->toStr() == "void()" || type1->toStr() == "void()")
    {
        fprintf(stderr, "type %s 为空 不能赋值",
                type1->toStr().c_str());
        exit(EXIT_FAILURE);
        return;
    }


    // 优化：提前计算常量表达式
    if (expr1->getSymPtr()->isConstant() && expr2->getSymPtr()->isConstant())
    {
        int value1 = dynamic_cast<ConstantSymbolEntry *>(expr1->getSymPtr())->getValue();
        int value2 = dynamic_cast<ConstantSymbolEntry *>(expr2->getSymPtr())->getValue();
        int result = 0;
        switch (op)
        {
        case ADD:
            result = value1 + value2;
            break;
        case SUB:
            result = value1 - value2;
            break;
        case MUL:
            result = value1 * value2;
            break;
        case DIV:
            result = value1 / value2;
            break;
        case MOD:
            result = value1 % value2;
            break;
        case AND:
            result = value1 && value2;
            break;
        case OR:
            result = value1 || value2;
            break;
        case LESS:
            result = value1 < value2;
            break;
        case GREATER:
            result = value1 > value2;
            break;
        case EQ:
            result = value1 == value2;
            break;
        case NEQ:
            result = value1 != value2;
            break;
        case GEQ:
            result = value1 >= value2;
            break;
        case LEQ:
            result = value1 <= value2;
            break;
        }
        SymbolEntry *se = new ConstantSymbolEntry(TypeSystem::intType, result);
        Constant *newNode = new Constant(se);
        *parentToChild = (Node *)newNode;
    }
}

void Constant::typeCheck(Node **parentToChild)
{
    // TODO: 实现常量的类型检查逻辑
}

void Id::typeCheck(Node **parentToChild)
{
    // TODO: 实现标识符的类型检查逻辑
    SymbolEntry *se = getSymPtr();
    std::string name = se->toStr();
}

void IfStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现 if 语句的类型检查逻辑
    cond->typeCheck((Node **)&(this->cond));
    if (cond->getSymPtr()->getType()->isInt() == 1)
    {
        cond->getSymPtr()->setType(TypeSystem::boolType);
    }
    else
    {
        if (cond->getSymPtr()->getType()->isFunc() == 1)
        {
            FunctionType *temp = static_cast<FunctionType *>(cond->getSymPtr()->getType());
            Type *tmp = temp->getRetType(); // 获得返回值类型
            if (tmp->isInt() == 1)
            {
                cond->getSymPtr()->setType(TypeSystem::boolType);
                thenStmt->typeCheck(nullptr);
                return;
            }
        }
        fprintf(stderr, "if语句条件类型不正确\n");
        exit(EXIT_FAILURE);
        return;
    }
}

void IfElseStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现 if-else 语句的类型检查逻辑
    cond->typeCheck((Node **)&(this->cond));
    // 1判断cond的类型 必须要是INT的(bool也是一种INT)
    if (cond->getSymPtr()->getType()->isInt() == 1)
    {
        cond->getSymPtr()->setType(TypeSystem::boolType);
    }
    else
    {
        if (cond->getSymPtr()->getType()->isFunc() == 1) // 函数类型
        {
            FunctionType *temp = static_cast<FunctionType *>(cond->getSymPtr()->getType());
            Type *tmp = temp->getRetType(); // 获取返回值
            if (tmp->isInt() == 1)
            {
                cond->getSymPtr()->setType(TypeSystem::boolType);
                thenStmt->typeCheck((Node **)&(this->thenStmt));
                elseStmt->typeCheck((Node **)&(this->thenStmt));
                return;
            }
        }
        fprintf(stderr, "ifelse语句条件类型不正确\n");
        exit(EXIT_FAILURE);
        return;
    }
    if (thenStmt != nullptr)
    {
        thenStmt->typeCheck((Node **)&(this->thenStmt));
    }
    else
    {
        thenStmt = nullptr;
    }
}

void CompoundStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现复合语句的类型检查逻辑
    if (stmt != NULL)
    {
        stmt->typeCheck(nullptr);
    }
}

void SeqNode::typeCheck(Node **parentToChild)
{
    // TODO: 实现序列节点的类型检查逻辑
    for (int i = 0; i < (int)stmtList.size(); ++i)
    {
        stmtList[i]->typeCheck((Node **)&(stmtList[i]));
    }
}

void DeclStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现声明语句的类型检查逻辑
    for (int i = 0; i < (int)defList.size(); ++i)
    {
        defList[i]->typeCheck(nullptr);
    }
}

void DefNode::typeCheck(Node **parentToChild)
{
    id->typeCheck(nullptr);
    // 不赋初值，直接返回
    if (initVal == nullptr)
    {
        return;
    }
    initVal->typeCheck((Node **)&(initVal));

    IdentifierSymbolEntry *se = (IdentifierSymbolEntry *)id->getSymPtr();
    se->value = ((ConstantSymbolEntry *)((ExprNode *)initVal)->getSymPtr())->getValue();

    if (dynamic_cast<IdentifierSymbolEntry *>(id->getSymPtr())->isGlobal())
    {
        // 对于初始化值不为空的，要进行初始化赋值
        if (initVal != nullptr)
        {
            IdentifierSymbolEntry *se = (IdentifierSymbolEntry *)id->getSymPtr();
            se->value = ((ConstantSymbolEntry *)((ExprNode *)initVal)->getSymPtr())->getValue();
        }

        // printf("value %d\n", se->value);
    }
}

void ContinueStmt::typeCheck(Node **parentToChild)
{
}

void BreakStmt::typeCheck(Node **parentToChild)
{
}

void ReturnStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现返回语句的添加类型检查逻辑
    if(returnType == nullptr){
        fprintf(stderr, "return statement outside functions\n");
        exit(EXIT_FAILURE);
    }
    else if(returnType->isVoid() && retValue!=nullptr){//returned a value in void()
        fprintf(stderr, "value returned in a void() function\n");
        exit(EXIT_FAILURE);
    }
    else if(!returnType->isVoid() && retValue==nullptr){//expected returned value, but returned nothing
        fprintf(stderr, "expected a %s type to return, but returned nothing\n", returnType->toStr().c_str());
        exit(EXIT_FAILURE);
    }
    if(!returnType->isVoid()){
        retValue->typeCheck((Node**)&(retValue));
    }
    this->retType = returnType;
    funcReturned = true;
}

void AssignStmt::typeCheck(Node **parentToChild)
{
    // TODO: 实现赋值语句的类型检查逻辑
    lval->typeCheck(nullptr);
    Type *type1 = lval->getSymPtr()->getType();
    expr->typeCheck((Node **)&(this->expr));
    Type *type2 = expr->getSymPtr()->getType();
    if (type1 != type2)
    {

        fprintf(stderr, "赋值语句中 type %s and %s 不匹配 xx",
                type1->toStr().c_str(), type2->toStr().c_str());
        exit(EXIT_FAILURE);
        return;
    }
    IdentifierSymbolEntry *se = (IdentifierSymbolEntry *)lval->getSymPtr();
    se->value = ((ConstantSymbolEntry *)((ExprNode *)expr)->getSymPtr())->getValue();
    printf("value %d\n", se->value);
}

void WhileStmt::typeCheck(Node **parentToChild)
{
    // 1判断cond的类型 必须要是INT的，并设置cond为bool
    if (Cond->getSymPtr()->getType()->isInt() == 1)
    {
        Cond->getSymPtr()->setType(TypeSystem::boolType);
    }
    else
    {
        fprintf(stderr, "while语句条件类型不正确\n");
        exit(EXIT_FAILURE);
        return;
    }
    // 对函数体进行类型检查
    stmt->typeCheck(nullptr);
}

void ForStmt::typeCheck(Node **parentToChild)
{
    // 1判断cond的类型 必须要是INT的，并设置cond为bool
    if (Cond->getSymPtr()->getType()->isInt() == 1)
    {
        Cond->getSymPtr()->setType(TypeSystem::boolType);
    }
    else
    {
        fprintf(stderr, "for语句条件类型不正确\n");
        exit(EXIT_FAILURE);
        return;
    }
    // 对函数体进行类型检查
    stmt->typeCheck(nullptr);
}

void IOStmt::typeCheck(Node **parentToChild)
{
}

void FunctionDef::typeCheck(Node **parentToChild)
{
    // 获取函数的返回值类型
    returnType = ((FunctionType *)se->getType())->getRetType();
    // 判断函数是否返回
    funcReturned = false;
    stmt->typeCheck(nullptr);
    // 非void类型的函数需要有返回值
    if (!funcReturned && !returnType->isVoid())
    {
        fprintf(stderr, "expected a %s type to return, but no returned value found\n", returnType->toStr().c_str());
        exit(EXIT_FAILURE);
    }
    returnType = nullptr;

}

void BinaryExpr::output(int level)
{
    std::string op_str;
    switch (op)
    {
    case ADD:
        op_str = "add";
        break;
    case SUB:
        op_str = "sub";
        break;
    case MUL:
        op_str = "mul";
        break;
    case DIV:
        op_str = "div";
        break;
    case MOD:
        op_str = "mod";
        break;
    case AND:
        op_str = "and";
        break;
    case OR:
        op_str = "or";
        break;
    case LESS:
        op_str = "less";
        break;
    case GREATER:
        op_str = "greater";
        break;
    case EQ:
        op_str = "equ";
        break;
    case NEQ:
        op_str = "noequ";
        break;
    case GEQ:
        op_str = "larand";
        break;
    case LEQ:
        op_str = "lesand";
        break;
    case NOT:
        op_str = "not";
        break;
    }

    fprintf(yyout, "%*cBinaryExpr\top: %s\n", level, ' ', op_str.c_str());
    expr1->output(level + 4);
    if (expr2 != nullptr)
        expr2->output(level + 4);
}



void Ast::output()
{
    fprintf(yyout, "program\n");
    if (root != nullptr)
        root->output(4);
}

void Constant::output(int level)
{
    std::string type, value;
    type = symbolEntry->getType()->toStr();
    value = symbolEntry->toStr();
    fprintf(yyout, "%*cInteger\tvalue: %s\ttype: %s\n", level, ' ',
            value.c_str(), type.c_str());
}

void Id::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    scope = dynamic_cast<IdentifierSymbolEntry *>(symbolEntry)->getScope();
    fprintf(yyout, "%*cId\tname: %s\tscope: %d\ttype: %s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void CompoundStmt::output(int level)
{
    fprintf(yyout, "%*cCompoundStmt\n", level, ' ');
    stmt->output(level + 4);
}

void SeqNode::addNext(StmtNode *next)
{
    stmtList.push_back(next);
}

void SeqNode::output(int level)
{
    fprintf(yyout, "%*cSequence\n", level, ' ');
    for (auto stmt : stmtList)
    {
        stmt->output(level + 4);
    }
}

void DeclStmt::addNext(DefNode *next)
{
    defList.push_back(next);
}

void DeclStmt::output(int level)
{
    fprintf(yyout, "%*cDeclStmt\n", level, ' ');
    for (auto def : defList)
    {
        def->output(level + 4);
    }
}

void DefNode::output(int level)
{

    fprintf(yyout, "%*cDefNoden\n", level, ' ');
    id->output(level + 4);
    if (initVal == nullptr)
    {
        fprintf(yyout, "%*cnull\n", level + 4, ' ');
    }
    else
    {
        initVal->output(level + 4);
    }
}

void IfStmt::output(int level)
{
    fprintf(yyout, "%*cIfStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
}

void IfElseStmt::output(int level)
{
    fprintf(yyout, "%*cIfElseStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
    elseStmt->output(level + 4);
}

void BreakStmt::output(int level)
{
    fprintf(yyout, "%*cBreakStmt\n", level, ' ');
}

void ContinueStmt::output(int level)
{
    fprintf(yyout, "%*cContinueStmt\n", level, ' ');
}

void ReturnStmt::output(int level)
{
    fprintf(yyout, "%*cReturnStmt\n", level, ' ');
    retValue->output(level + 4);
}

void AssignStmt::output(int level)
{
    fprintf(yyout, "%*cAssignStmt\n", level, ' ');
    lval->output(level + 4);
    expr->output(level + 4);
}

void WhileStmt::output(int level)
{
    fprintf(yyout, "%*cWhileStmt\n", level, ' ');
    Cond->output(level + 4);
    stmt->output(level + 4);
}

void ForStmt::output(int level)
{
    fprintf(yyout, "%*cForStmt\n", level, ' ');
    initStmt->output(level + 4);
    Cond->output(level + 4);
    loopStmt->output(level + 4);
    stmt->output(level + 4);
}

void IOStmt::output(int level)
{
    
    if (op == PRINT)
    {
        fprintf(yyout, "%*cIOStmt op: print\n", level, ' ');
    }
    else
    {
        fprintf(yyout, "%*cIOStmt op: scan\n", level, ' ');
    }
    expr->output(level + 4);
}

void FunctionDef::output(int level)
{
    std::string name, type;
    name = se->toStr();
    type = se->getType()->toStr();
    fprintf(yyout, "%*cFunctionDefine function name: %s, type: %s\n", level, ' ',
            name.c_str(), type.c_str());
    stmt->output(level + 4);

}
